package com.bzchao;

import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vosk.LibVosk;
import org.vosk.LogLevel;
import org.vosk.Model;
import org.vosk.Recognizer;

import javax.sound.sampled.AudioInputStream;
import java.io.*;

public class VoskUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(VoskUtils.class);
    //语音模型释放目录
    public static final String RELEASE_VOSK_DIR = System.getProperty("user.home") + "/vosk";
    //语音模型最终目录
    public static final String MODEL_PATH = RELEASE_VOSK_DIR + "/vosk-model-small-cn-0.22";
    //是否已经释放语音模型
    public static boolean isRelease = false;

    static {
        // initLibs();
    }

    /**
     * 解决部分linux缺少so文件
     */
    private static void initLibs() {
        String osName = System.getProperties().getProperty("os.name");
        if (osName.equals("Linux")) {
            try {
                FileUtils.forceMkdir(new File(RELEASE_VOSK_DIR + "/libs"));
                String file1 = "/vosk/libs/libatomic.so.1";
                String file2 = "/vosk/libs/libatomic.so.1.0.0";
                FileUtils.copyInputStreamToFile(VoskUtils.class.getResourceAsStream(file1), new File(RELEASE_VOSK_DIR + "/libs/libatomic.so.1"));
                FileUtils.copyInputStreamToFile(VoskUtils.class.getResourceAsStream(file2), new File(RELEASE_VOSK_DIR + "/libs/libatomic.so.1.0.0"));
                System.load(RELEASE_VOSK_DIR + "/libs/libatomic.so.1.0.0");
                LOGGER.info("加载vosk-libs成功{}");
            } catch (Exception e) {
                LOGGER.error("加载libs失败{}", e.getMessage(), e);
            }
        }
    }

    /**
     * @param audioInput 仅支持wav文件件
     * @return
     */
    public static String reAudioToText(AudioInputStream audioInput) throws IOException {
        LibVosk.setLogLevel(LogLevel.DEBUG);

        float sampleRate = audioInput.getFormat().getSampleRate();
        Model model = new Model(MODEL_PATH);
        Recognizer recognizer = new Recognizer(model, sampleRate);

        byte[] bytes1 = IOUtils.toByteArray(audioInput);
        recognizer.acceptWaveForm(bytes1, bytes1.length);

        return recognizer.getFinalResult();
    }

    /**
     * 释放resource目录下的vosk文件
     */
    public static void releaseVoskDir() throws IOException {
        File mdlFile = new File(MODEL_PATH + "/am/final.mdl");
        if (isRelease && mdlFile.exists()) {
            return;
        }
        initLibs();
        LOGGER.info("开始释放语言识别模型isRelease={},mdlFile={}", isRelease, mdlFile.exists());
        File dest = new File(RELEASE_VOSK_DIR);
        FileUtils.forceMkdir(dest);

        InputStream resourceIn = VoskUtils.class.getClassLoader().getResourceAsStream("vosk/vosk-model-small-cn-0.22.zip");
        ZipArchiveInputStream zipArchiveInputStream = new ZipArchiveInputStream(new BufferedInputStream(resourceIn));
        unpackZip(zipArchiveInputStream, dest);
        isRelease = true;
    }

    /**
     * 文件解压
     */
    public static void unpackZip(ZipArchiveInputStream inputStream, File descDir) {
        try {
            if (!descDir.exists()) {
                descDir.mkdirs();
            }
            ZipArchiveEntry entry = null;
            while ((entry = inputStream.getNextZipEntry()) != null) {
                if (entry.isDirectory()) {
                    File directory = new File(descDir, entry.getName());
                    directory.mkdirs();
                } else {
                    OutputStream os = null;
                    try {
                        os = new BufferedOutputStream(new FileOutputStream(new File(descDir, entry.getName())));
                        //输出文件路径信息
                        System.out.println("解压文件的当前路径为:" + descDir + entry.getName());
                        IOUtils.copy(inputStream, os);
                    } finally {
                        IOUtils.closeQuietly(os);
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static ZipArchiveInputStream getZipFile(File zipFile) throws Exception {
        return new ZipArchiveInputStream(new BufferedInputStream(new FileInputStream(zipFile)));
    }

}
